'''
1. 以Lena为原始图像，通过OpenCV实现平均滤波，高斯滤波及中值滤波，比较滤波结果。
'''
'''
import cv2 as cv

filename = r'D:\python\jjj\data\lena.jpg'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)

imgblur = cv.blur(img,(3,3),0)
imgGau = cv.GaussianBlur(img,(3,3),5)
imgmed = cv.medianBlur(img,5)
''''''
滤波结果,基本一致。中值滤波的参数选取越大越模糊；高斯滤波以模板为准，模板越大，越模糊。
平均滤波,基本与高斯滤波一致。在相同模板下，高斯滤波的权重值越大，比起平均滤波越较清晰
'''
'''

img = cv.pyrDown(img)
imgblur = cv.pyrDown(imgblur)
imgGau = cv.pyrDown(imgGau)
imgmed = cv.pyrDown(imgmed)


cv.imshow("Source image",img)
cv.imshow("Blur",imgblur)
cv.imshow("Gau",imgGau)
cv.imshow("Med",imgmed)

cv.waitKey()
cv.destroyAllWindows()
'''

'''
#2
import cv2 as cv

filename = r'D:\python\jjj\data\lena.jpg'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)

imgS1 = cv.Sobel(img,cv.CV_16S,1,1)
imgS2 = cv.Sobel(gray,cv.CV_16S,1,1)
''''''
Sobel算子，边缘检测容易重叠形成两条线，并且误检漏检比较Canny算子 更多一些。
可以检测出大概的lena图像，但背景处理上，就不行了。
''''''
imgCanny = cv.Canny(gray,10,120)
imgCanny1 = cv.Canny(gray,50,120)
imgCanny2 = cv.Canny(gray,100,200)
''''''
而Canny算子，边缘检测是比较得体的，无论在前景或者背景。其次，Canny算子的
''''''

imgS1 = cv.convertScaleAbs(imgS1)   # 转回uint8
imgS2 = cv.convertScaleAbs(imgS2)

cv.imshow(" ",img)
cv.imshow("Sobel",imgS1)
cv.imshow("Sobel 2",imgS2)
cv.waitKey()

cv.imshow("Canny",imgCanny)
cv.imshow("Canny1",imgCanny1)
cv.imshow("Canny2",imgCanny2)

cv.waitKey()
cv.destroyAllWindows()
'''

#3
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

filename = r'D:\python\jjj\ml.png'
ima = cv.imread(filename)
gray = cv.cvtColor(ima,cv.COLOR_BGR2GRAY)# 灰度空间转换

'hist = cv2.calcHist([img], [0], None, [256], [0, 256])'
hist = cv.calcHist([ima],[0],None,[256],[0,256])
#[0]：输出通道，None：Mask，[256]：256个直方图，最后为范围
ret1,th1 = cv.threshold(gray,0,255,cv.THRESH_OTSU)
#ret1为类间方差（阈值值）；0为自动寻找阈值；255为最大阈值，后为大津算法

cv.imshow("gray",gray)
cv.imshow("OTSU",th1)
plt.hist(ima.ravel(),256,[0,256])#构造直方图。256个直方图，范围
plt.show()

cv.waitKey(0)
cv.destroyAllWindows()

'''
OTSU算法：在米粒图上，图片下方有许多的信息缺失，并且对噪声很敏感，阈值化图中，噪声明显。
从直方图可以看出，米粒图中的灰度分布。
'''

''''
#4
# encoding:utf-8
import cv2 as cv
import copy
import numpy as np
from matplotlib import pyplot as plt


'图像采集：'
filename = r'D:\python\jjj\ml.png'
image = cv.imread(filename)

'图像处理：'
gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY) #转换灰度图像
imgGau = cv.GaussianBlur(gray,(3,3),0)
#img1 = cv.medianBlur(gray,5)
#_, bw = cv.threshold(gray,0,0xff,cv.THRESH_OTSU) #使用大津算法，将图像进行分割
threshold = cv.adaptiveThreshold(imgGau,0xff,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,91,0)#局部大津算法
' gray：原图像；0，0xff : 当前阈值 最大阈值  阈值化类型：大津算法   返回结果图像和当前阈值'
element = cv.getStructuringElement(cv.MORPH_CROSS,(3,3))#返回指定形状和尺寸的结构元素
'MORPH_CROSS:交叉型结构元素 在开运算中，以此元素进行'
bw = cv.morphologyEx(threshold,cv.MORPH_OPEN,element)#开运算，减少噪声

seg = copy.deepcopy(bw) #将seg图像与bw图像进行深拷贝，为的边缘轮廓修改
_,cnts,hier = cv.findContours(seg,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)#边缘轮廓
'返回值：所处理的原图像seg = bin ，cnts：轮廓的点集，hier：轮廓的索引'
'参数：处理图像，只检测外层轮廓，只保留终点坐标'
count = 0 #初值
area_list = []
len_list = []

'米粒计算器'
for i in range(len(cnts),0,-1):
    c = cnts[i-1]
    area = cv.contourArea(c)
    len = cv.arcLength(c,True)
    if area < 10:
        continue
    count += 1
    area_list.append(area)
    len_list.append(len)
    #x,y,w,h = cv.boundingRect(c)#最小包围矩形1
    '返回值：x,y:左上点坐标，w,h：矩阵的宽和高'
    #cv.rectangle(image,(x,y),(x+w,y+h),(0,0xff,0),1)#画出矩形
    '参数：原图，(x,y)：矩阵左上点坐标，(x+w,y+h):矩阵右下坐标  画线的RGB颜色  画线的宽度'
    #cv.putText(image,str(count),(x,y),cv.FONT_HERSHEY_PLAIN,0.6,(0xff,0,0xff))#标记矩形，添加文字
    'cv2.putText(img, str(i), (123,456)), font, 2, (0,255,0), 3) '
    '各参数依次是：图片，添加的文字，左上角坐标，字体，字体大小，颜色，字体粗细'
    rect = cv.minAreaRect(c)# 得到最小外接矩形的（中心(x,y), (宽,高), 旋转角度）
    box = cv.cv2.boxPoints(rect)# cv2.boxPoints(rect) for OpenCV 3.x 获取最小外接矩形的4个顶点坐标
    box = np.int0(box)
    box_tuple = tuple(box[0])
    cv.drawContours(image, [box], 0, (0, 0, 0xff), 1)
    print('区域：%d : 面积为：%d 长度为：%d' % (i,area,len))
    cv.putText(image, str(count),(box_tuple),cv.FONT_HERSHEY_PLAIN, 0.6, (0, 0xff, 0))
    #cv.imwrite('contours.png', image)

#长度、面积均值:
avg_area = np.mean(area_list)
avg_len = np.mean(len_list)
#方差
var_area = np.var(area_list)
var_len = np.var(len_list)
print('米粒的面积均值：%.2f 方差为：%.2f'%(avg_area,var_area))
print('米粒的长度均值：%.2f 方差为：%.2f'%(avg_len,var_len))

#3σ范围内的数量（根据面积）
std_area = var_area ** 0.5 #标准差
up_area = avg_area + 3 * std_area#右
down_area = avg_area - 3 * std_area#左
x = np.array(area_list)
area_3_size = x[(x >= down_area) & (x <= up_area)].size
print('米粒总数量：%d,据面积米粒在3sigma范围内数量：%d' % (count,area_3_size))

#3σ范围内的数量（根据周长）
std_len = var_len ** 0.5
up_len = avg_len + 3 * std_len
down_len = avg_len + 3 * std_len
y = np.array(len_list)
len_3_size = y[(y >= down_len) & (y <= up_len)].size
print('米粒总数量：%d,据周长米粒在3sigma范围内数量：%d' % (count,len_3_size))

#原图、高斯模糊、阈值图
cv.imshow("image",image)
cv.imshow("Gau",imgGau)
cv.imshow("gray",gray)

#面积直方图
plt.subplot(2,2,3)
plt.hist(area_list)
plt.title("area")

#周长直方图
plt.subplot(2,2,4)
plt.hist(len_list)
plt.title("length")

plt.show()

#cv.imshow("threshold",bw)
#cv.imshow("threshold2",threshold)
#cv.imshow("",bin)

cv.waitKey()
cv.destroyAllWindows()
'''


''''
#5
import cv2 as cv
from matplotlib import pyplot as plt

def sift_check(input_img):
    gray_img = cv.cvtColor(input_img,cv.COLOR_BGR2GRAY)#灰度输入图像
    blur_img = cv.GaussianBlur(gray_img,(3,3),0)#将灰度图像高斯模糊
    #SIFT算子检测
    sift = cv.xfeatures2d.SIFT_create()#创建算子
    kp1 = sift.detect(blur_img,None)#计算关键点
    sift_result = blur_img.copy()
    sift_result = cv.drawKeypoints(gray_img,kp1,sift_result,(0xff,0,0xff))#画出关键点
    return sift_result

def orb_check(input_img):
    gray_img = cv.cvtColor(input_img,cv.COLOR_BGR2GRAY)
    blur_img = cv.GaussianBlur(gray_img,(3,3),0)
    #ORB算子
    orb = cv.ORB_create()#ORB算子创建
    kp = orb.detect(blur_img,None)#关键点检测
    orb_result = blur_img.copy()
    orb_result = cv.drawKeypoints(gray_img,kp,orb_result,(0xff,0,0xff))#标记关键点
    return orb_result

def fast_check(intput_img):
    gray_img = cv.cvtColor(intput_img,cv.COLOR_BGR2GRAY)
    blur_img = cv.GaussianBlur(gray_img,(3,3),0)
    #FAST
    fast = cv.FastFeatureDetector_create()#创建FAST算子
    kp = fast.detect(blur_img,None)#关键点检测
    fast_result = blur_img.copy()
    fast_result = cv.drawKeypoints(gray_img,kp,fast_result,(0xff,0,0xff))#标记关键点
    return fast_result

def main():
    src = cv.imread(r'D:\AI\jjj\t1.jpg')
    sift_img = sift_check(src)
    fast_img = fast_check(src)
    orb_img = orb_check(src)
    imgs = [src,sift_img,fast_img,orb_img]
    titles = ['src_img','sift_img','fast_img','orb_img']
    for i in range(4):
        plt.subplot(2,2,i+1)
        plt.imshow(imgs[i])
        plt.title(titles[i])
        plt.axis('off')
        plt.subplots_adjust(0.1,0.1)

    plt.show()

if __name__ == '__main__':
    main()

'''
'''
SIFT在检测特征点上，基数大，基本都能够检测，能够符合基本要求的使用，缺点，有存在误检、漏检,许多特征点粘连性强。
FAST检测特征：FAST比起SIFT基数更为庞大，点对粘连性更强，误检更多，也基本可以描述出物体，
ORB：特征点极少，误检比之少了许多，
'''
